// $Id: type_info.hpp 2 2009-09-02 08:47:42Z joseph2002 $
/*
 * Copyright 2009 Joseph Wu
 * Distributed under the Boost Software License, Version 1.0.
 * (See accompanying file LICENSE_1_0.txt or http://www.boost.org/LICENSE_1_0.txt)
 *
 * For more information, see http://xpcomplus.sourceforge.net
 */

#ifndef XPCOM_TYPE_INFO_HPP
#define XPCOM_TYPE_INFO_HPP

#include <xpcom/config.hpp>
#include <xpcom/uuid.hpp>

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_PREFIX
#endif

namespace xpcom {

//
// Provide access to uuid/contractid/name and base type of objects.
//
// type_info is typically specialized for certain types. The primary template
// is implemented by forwarding to T::type.
//
template <typename T>
struct type_info : public type_info<typename T::type>
{
};

//
// Type info accessor
//
template <typename T>
inline const uuid& typeid_of(T* = 0)
{
    return type_info<T>::id();
}

template <typename T>
inline const char* contractid_of(T* = 0)
{
    return type_info<T>::contractid();
}

template <typename T>
inline const char* name_of(T* = 0)
{
    return type_info<T>::name();
}

} // namespace xpcom

//
// Helper macro for defining type_info values.
//
// Some times, internal interfaces need to defined manually without code
// generation. You can specialize your own type_info like this:
//
//  XPCOM_TYPE_INFO_DECL(Foo, base-of-foo)
//  XPCOM_TYPE_INFO_ID(Foo, uuid-of-Foo)
//
// The uuid should be in the form of:
//  { 0x00000000, 0x0000, 0x0000,
//  { 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00 } }
//
// Optionally, you can define the contractid and name also:
//  XPCOM_TYPE_INFO_CONTRACTID(Foo, "foo@foo.org/1")
//  XPCOM_TYPE_INFO_NAME(Foo, "org.Foo")
//
#define XPCOM_TYPE_INFO_DECL(_type, _base_type) \
    template <> \
    struct type_info<_type> \
    { \
        typedef _type type; \
        typedef _base_type base_type; \
        template <typename Dummy> \
        struct value_holder \
        { \
            static const uuid id; \
            static const char contractid[]; \
            static const char name[]; \
        }; \
        typedef value_holder<int> value_holder_type; \
        static const uuid& id() { return value_holder_type::id; } \
        static const char* contractid() { return value_holder_type::contractid; } \
        static const char* name() { return value_holder_type::name; } \
    };

#define XPCOM_TYPE_INFO_ID(type, \
    _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9, _i10, _i11) \
    template <typename Dummy> \
    const uuid type_info<type>::value_holder<Dummy>::id = \
        _i1, _i2, _i3, _i4, _i5, _i6, _i7, _i8, _i9, _i10, _i11;

#define XPCOM_TYPE_INFO_CONTRACTID(type, _c) \
    template <typename Dummy> \
    const char type_info<type>::value_holder<Dummy>::contractid[] = _c;

#define XPCOM_TYPE_INFO_NAME(type, _n) \
    template <typename Dummy> \
    const char type_info<type>::value_holder<Dummy>::name[] = _n;

#ifdef BOOST_HAS_ABI_HEADERS
#include BOOST_ABI_SUFFIX
#endif

#endif // XPCOM_TYPE_INFO_HPP
